#pragma once
// #include "utils/logging.h"
// #include <H5Dpublic.h>
// #include <H5Ppublic.h>
// #include <H5Spublic.h>
// #include <H5Tpublic.h>
// #include <H5public.h>
// #include <H5version.h>
#include <cstdint>
#include <hdf5.h>
#include <array>
#include <string>
#include <vector>

#define CHECK_RESOURCE_ID_AND_RETURN(resource_id, result) \
    if (resource_id < 0) {                                \
        return result;                                    \
    }

namespace h5 {
constexpr hid_t INVALID_HDF5_RESOURCE_ID = -1;
// this function will create new instance each invoke!
template<class T> hid_t get_dtype_id();
// for the simple dtype
// support in the future!
class float16 {};

template<> inline hid_t get_dtype_id<uint8_t>() {
    return H5T_NATIVE_UINT8;
}

template<> inline hid_t get_dtype_id<int8_t>() {
    return H5T_NATIVE_INT8;
}

template<> inline hid_t get_dtype_id<uint16_t>() {
    return H5T_NATIVE_UINT16;
}

template<> inline hid_t get_dtype_id<int16_t>() {
    return H5T_NATIVE_INT16;
}

template<> inline hid_t get_dtype_id<uint32_t>() {
    return H5T_NATIVE_UINT32;
}

template<> inline hid_t get_dtype_id<int32_t>() {
    return H5T_NATIVE_INT32;
}

template<> inline hid_t get_dtype_id<uint64_t>() {
    return H5T_NATIVE_UINT64;
}

template<> inline hid_t get_dtype_id<int64_t>() {
    return H5T_NATIVE_INT64;
}

template<> inline hid_t get_dtype_id<float>() {
    return H5T_NATIVE_FLOAT;
}

template<> inline hid_t get_dtype_id<double>() {
    return H5T_NATIVE_DOUBLE;
}

template<> inline hid_t get_dtype_id<float16>() {
    return -1;
}

template<size_t N> inline hid_t get_dtype_id_fixed_str() {
    hid_t dtype_id = H5Tcopy(H5T_C_S1);
    H5Tset_size(dtype_id, N);
    return dtype_id;
}

using fixed_s32_t = std::array<char, 32>;
template<> inline hid_t get_dtype_id<fixed_s32_t>() {
    return get_dtype_id_fixed_str<32>();
}

using fixed_s64_t = std::array<char, 64>;
template<> inline hid_t get_dtype_id<fixed_s64_t>() {
    return get_dtype_id_fixed_str<64>();
}
bool is_builtin_dtype_id(hid_t type_id);
enum class SimpleHDF5ResourceKind {
    file             = 0,
    group            = 1,
    dataset          = 2,
    dataspace        = 3,
    attribute        = 4,
    structured_dtype = 5,
    property         = 6,
    builtin_dtype    = 7,
    other            = 8
};

SimpleHDF5ResourceKind get_resource_kind(hid_t resource_id);

class SimpleHDF5ResourceManager {
private:
    hid_t id;

public:
    explicit SimpleHDF5ResourceManager(hid_t id_)
        : id(id_) {}
    SimpleHDF5ResourceManager()                                     = delete;
    SimpleHDF5ResourceManager(const SimpleHDF5ResourceManager& rhs) = delete;
    SimpleHDF5ResourceManager(SimpleHDF5ResourceManager&& rhs) noexcept
        : id(rhs.id) {
        rhs.id = INVALID_HDF5_RESOURCE_ID;
    }
    SimpleHDF5ResourceManager& operator=(const SimpleHDF5ResourceManager& rhs) = delete;
    SimpleHDF5ResourceManager& operator=(SimpleHDF5ResourceManager&& rhs) {
        this->release();
        id     = rhs.id;
        rhs.id = INVALID_HDF5_RESOURCE_ID;
        return *this;
    }


    void release() {
        if (id > 0) {
            SimpleHDF5ResourceKind kind = get_resource_kind(id);
            switch (kind) {
            case SimpleHDF5ResourceKind::file: H5Fclose(id); break;
            case SimpleHDF5ResourceKind::group: H5Gclose(id); break;
            case SimpleHDF5ResourceKind::dataset: H5Dclose(id); break;
            case SimpleHDF5ResourceKind::dataspace: H5Sclose(id); break;
            case SimpleHDF5ResourceKind::attribute: H5Aclose(id); break;
            case SimpleHDF5ResourceKind::structured_dtype: H5Tclose(id); break;
            case SimpleHDF5ResourceKind::property: H5Pclose(id); break;
            default: break;
            }
        }
        id = INVALID_HDF5_RESOURCE_ID;
    }
    ~SimpleHDF5ResourceManager() { this->release(); }
};

#define RESOURCE_PREFIX hdf5_resource_id_placeholder_
#define CONCAT_IMPL(x, y) x##y
#define CONCAT(x, y) CONCAT_IMPL(x, y)
#define UNIQUE_VAR_NAME(prefix) CONCAT(prefix, __LINE__)
#define DECLARE_HDF5_RESOURCE_MANAGER(ID) \
    ::h5::SimpleHDF5ResourceManager UNIQUE_VAR_NAME(RESOURCE_PREFIX)(ID);

enum class CompressFilterType : int {
    FilterDefalte     = 0,
    FilterShuffle     = 1,
    FilterFlecher32   = 2,
    FilterSzip        = 3,
    FilterScaleOffset = 4,
    FilterZstd        = 5,
    FilterNbit        = 6,
    FilterOther       = 7
};
CompressFilterType get_dataset_filter_type(hid_t dataset_id);
constexpr int      IS_HDF5_FORMAT_FLAG = 1;


hid_t open_file_without_file_locking(const char* file);
hid_t open_file_without_file_locking(const std::string& file);

hid_t create_file_with_auto_flush(const char* file);
hid_t create_file_with_auto_flush(const std::string& file);

bool                     is_link_exist(hid_t loc_id, const char* name);
bool                     is_link_exist(hid_t loc_id, const std::string& name);
std::vector<std::string> get_sub_names(hid_t loc_id);
std::string              get_first_sub_name(hid_t loc_id);


template<class T>
bool read_from_dataset(hid_t dataset_id, hid_t dataset_space_id, hid_t result_space_id,
                       hsize_t start, hsize_t len, std::vector<T>& result) {
    if (result.size() < len) {
        return false;
    }
    // invalid len
    if (start < 0 || len <= 0) {
        return false;
    }
    if (H5Sget_simple_extent_ndims(dataset_space_id) != 1 ||
        H5Sget_simple_extent_ndims(result_space_id) != 1) {
        return false;
    }
    hsize_t n = 0;
    H5Sget_simple_extent_dims(dataset_space_id, &n, nullptr);
    if (start >= n || (start + len) > n) {
        return false;
    }

    H5Sget_simple_extent_dims(result_space_id, &n, nullptr);
    if (n < len) {
        return false;
    }
    if (H5Sselect_hyperslab(dataset_space_id, H5S_SELECT_SET, &start, nullptr, &len, nullptr) < 0) {
        return false;
    }
    const hsize_t fly = 0;
    if (H5Sselect_hyperslab(result_space_id, H5S_SELECT_SET, &fly, nullptr, &len, nullptr) < 0) {
        return false;
    }
    // here no need to take care of release for static type id!
    hid_t type_id = get_dtype_id<T>();
    CHECK_RESOURCE_ID_AND_RETURN(type_id, false);
    DECLARE_HDF5_RESOURCE_MANAGER(type_id);

    if (H5Dread(
            dataset_id, type_id, result_space_id, dataset_space_id, H5P_DEFAULT, result.data()) <
        0) {
        return false;
    }
    return true;
}

template<class T>
bool read_from_dataset(hid_t dataset_id, hsize_t start, hsize_t len, std::vector<T>& result) {
    CHECK_RESOURCE_ID_AND_RETURN(dataset_id, false);

    hid_t space_id = H5Dget_space(dataset_id);
    CHECK_RESOURCE_ID_AND_RETURN(space_id, false);
    DECLARE_HDF5_RESOURCE_MANAGER(space_id);

    result.resize(len);

    hid_t result_space_id = H5Screate_simple(1, &len, nullptr);
    CHECK_RESOURCE_ID_AND_RETURN(result_space_id, false);
    DECLARE_HDF5_RESOURCE_MANAGER(result_space_id);

    return read_from_dataset(dataset_id, space_id, space_id, start, len, result);
}

template<class T> bool read_from_dataset(hid_t dataset_id, std::vector<T>& result) {
    hid_t space_id = H5Dget_space(dataset_id);
    if (space_id < 0) {
        return false;
    }
    DECLARE_HDF5_RESOURCE_MANAGER(space_id);
    hsize_t n    = 0;
    int     ndim = H5Sget_simple_extent_ndims(space_id);
    if (ndim != 1) {
        return false;
    }
    H5Sget_simple_extent_dims(space_id, &n, nullptr);
    result.resize(n);
    hid_t type_id = get_dtype_id<T>();
    CHECK_RESOURCE_ID_AND_RETURN(type_id, false);
    DECLARE_HDF5_RESOURCE_MANAGER(type_id);
    if (H5Dread(dataset_id, type_id, H5S_ALL, H5S_ALL, H5P_DEFAULT, result.data()) < 0) {
        return false;
    }
    return true;
}

inline bool is_attribute_exist(hid_t loc_id, const char* name) {
    if (loc_id <= 0) {
        return false;
    }
    bool has_attr = (H5Aexists(loc_id, name) > 0);
    return has_attr;
}

template<class T> bool read_attribute(hid_t loc_id, const char* name, T& value) {
    if (loc_id < 0 || !name) {
        return false;
    }
    if (!is_attribute_exist(loc_id, name)) {
        return false;
    }
    hid_t attr_id = H5Aopen(loc_id, name, H5P_DEFAULT);
    if (attr_id < 0) {
        return false;
    }

    DECLARE_HDF5_RESOURCE_MANAGER(attr_id);
    hid_t space_id = H5Aget_space(attr_id);
    if (space_id < 0) {
        return false;
    }
    DECLARE_HDF5_RESOURCE_MANAGER(space_id);
    auto element_size = H5Sget_simple_extent_npoints(space_id);
    if (element_size != 1) {
        return false;
    }
    hid_t given_dtype_id = get_dtype_id<T>();
    CHECK_RESOURCE_ID_AND_RETURN(given_dtype_id, false);
    DECLARE_HDF5_RESOURCE_MANAGER(given_dtype_id);

    // the simple dtype no need to close explictly!
    return H5Aread(attr_id, given_dtype_id, &value) == 0;
}

template<class T> bool write_attribute(hid_t loc_id, const char* name, T value) {
    if (loc_id < 0 || name == nullptr) {
        return false;
    }
    if (is_attribute_exist(loc_id, name)) {
        return false;
    }
    hid_t        dtype_id        = get_dtype_id<T>();
    static hid_t scalar_space_id = H5Screate(H5S_SCALAR);

    hid_t attr_id = H5Acreate(loc_id, name, dtype_id, scalar_space_id, H5P_DEFAULT, H5P_DEFAULT);
    if (attr_id < 0) {
        return false;
    }
    DECLARE_HDF5_RESOURCE_MANAGER(attr_id);
    herr_t status = H5Awrite(attr_id, dtype_id, &value);
    return status >= 0;
}


template<class T> bool compat_write_attribute(hid_t loc_id, const char* name, T value) {
    if (loc_id < 0 || name == nullptr) {
        return false;
    }
    if (is_attribute_exist(loc_id, name)) {
        return false;
    }
    hid_t         dtype_id        = get_dtype_id<T>();
    const hsize_t compat_len      = 1;
    static hid_t  compat_space_id = H5Screate_simple(1, &compat_len, nullptr);


    hid_t attr_id = H5Acreate(loc_id, name, dtype_id, compat_space_id, H5P_DEFAULT, H5P_DEFAULT);
    if (attr_id < 0) {
        return false;
    }
    DECLARE_HDF5_RESOURCE_MANAGER(attr_id);
    herr_t status = H5Awrite(attr_id, dtype_id, &value);
    return status >= 0;
}


template<class T>
bool write_attribute(hid_t loc_id, const char* name, const T* value_ptr, size_t len) {
    if (loc_id < 0 || name == nullptr || value_ptr == nullptr) {
        return false;
    }
    if (is_attribute_exist(loc_id, name)) {
        return false;
    }

    hsize_t dims[1]  = {static_cast<hsize_t>(len)};
    hid_t   space_id = H5Screate_simple(1, dims, nullptr);
    if (space_id < 0) {
        return false;
    }

    DECLARE_HDF5_RESOURCE_MANAGER(space_id);
    hid_t dtype_id = get_dtype_id<T>();
    hid_t attr_id  = H5Acreate(loc_id, name, dtype_id, space_id, H5P_DEFAULT, H5P_DEFAULT);
    if (attr_id < 0) {
        return false;
    }
    DECLARE_HDF5_RESOURCE_MANAGER(attr_id);
    herr_t status = H5Awrite(attr_id, dtype_id, value_ptr);
    return status >= 0;
}

inline bool write_attribute(hid_t loc_id, const char* name, const char* value) {
    if (loc_id < 0 || name == nullptr || value == nullptr) {
        return false;
    }   // for the valen string data,should wrap it!
    const char* wrap_value[1] = {value};
    if (is_attribute_exist(loc_id, name)) {
        return false;
    }
    hid_t type_id = H5Tcopy(H5T_C_S1);
    H5Tset_size(type_id, H5T_VARIABLE);
    if (type_id < 0) {
        return false;
    }
    DECLARE_HDF5_RESOURCE_MANAGER(type_id);
    static hid_t scalar_space_id = H5Screate(H5S_SCALAR);
    hid_t attr_id = H5Acreate(loc_id, name, type_id, scalar_space_id, H5P_DEFAULT, H5P_DEFAULT);
    if (attr_id < 0) {
        return false;
    }
    DECLARE_HDF5_RESOURCE_MANAGER(attr_id);
    auto status = H5Awrite(attr_id, type_id, wrap_value);
    return status >= 0;
}

inline bool write_attribute(hid_t loc_id, const char* name, const char* value,
                            size_t fixed_str_len) {
    if (loc_id < 0 || name == nullptr || value == nullptr) {
        return false;
    }   // for the valen string data,should wrap it!
    if (is_attribute_exist(loc_id, name)) {
        return false;
    }
    hid_t type_id = H5Tcopy(H5T_C_S1);
    H5Tset_size(type_id, fixed_str_len);
    if (type_id < 0) {
        return false;
    }
    DECLARE_HDF5_RESOURCE_MANAGER(type_id);
    static hid_t scalar_space_id = H5Screate(H5S_SCALAR);
    hid_t attr_id = H5Acreate(loc_id, name, type_id, scalar_space_id, H5P_DEFAULT, H5P_DEFAULT);
    if (attr_id < 0) {
        return false;
    }
    DECLARE_HDF5_RESOURCE_MANAGER(attr_id);
    auto status = H5Awrite(attr_id, type_id, value);
    return status >= 0;
}

inline bool write_attribute(hid_t loc_id, const char* name, const char* value, size_t len,
                            size_t fixed_str_len) {
    if (loc_id < 0 || name == nullptr || value == nullptr) {
        return false;
    }   // for the valen string data,should wrap it!
    if (is_attribute_exist(loc_id, name)) {
        return false;
    }
    hid_t type_id = H5Tcopy(H5T_C_S1);
    H5Tset_size(type_id, fixed_str_len);
    if (type_id < 0) {
        return false;
    }
    DECLARE_HDF5_RESOURCE_MANAGER(type_id);

    hsize_t dims[1]  = {static_cast<hsize_t>(len)};
    hid_t   space_id = H5Screate_simple(1, dims, nullptr);
    if (space_id < 0) {
        return false;
    }
    DECLARE_HDF5_RESOURCE_MANAGER(space_id);
    hid_t attr_id = H5Acreate(loc_id, name, type_id, space_id, H5P_DEFAULT, H5P_DEFAULT);
    if (attr_id < 0) {
        return false;
    }
    DECLARE_HDF5_RESOURCE_MANAGER(attr_id);
    auto status = H5Awrite(attr_id, type_id, value);
    return status >= 0;
}

inline bool write_attribute(hid_t loc_id, const char* name, const char* const* value_ptr,
                            size_t len) {
    if (loc_id < 0 || name == nullptr || value_ptr == nullptr) {
        return false;
    }
    if (is_attribute_exist(loc_id, name)) {
        return false;
    }
    hid_t type_id = H5Tcopy(H5T_C_S1);
    H5Tset_size(type_id, H5T_VARIABLE);
    if (type_id < 0) {
        return false;
    }

    DECLARE_HDF5_RESOURCE_MANAGER(type_id);
    hsize_t dims[1]  = {static_cast<hsize_t>(len)};
    hid_t   space_id = H5Screate_simple(1, dims, nullptr);

    hid_t attr_id = H5Acreate(loc_id, name, type_id, space_id, H5P_DEFAULT, H5P_DEFAULT);
    if (attr_id < 0) {
        return false;
    }
    DECLARE_HDF5_RESOURCE_MANAGER(attr_id);
    auto status = H5Awrite(attr_id, type_id, value_ptr);
    return status >= 0;
}

inline bool write_attribute(hid_t loc_id, const char* name, const char* const* value_ptr,
                            size_t len, size_t fixed_str_len) {
    if (loc_id < 0 || name == nullptr || value_ptr == nullptr) {
        return false;
    }
    if (is_attribute_exist(loc_id, name)) {
        return false;
    }
    hid_t type_id = H5Tcopy(H5T_C_S1);
    H5Tset_size(type_id, fixed_str_len);
    if (type_id < 0) {
        return false;
    }

    DECLARE_HDF5_RESOURCE_MANAGER(type_id);
    hsize_t dims[1]  = {static_cast<hsize_t>(len)};
    hid_t   space_id = H5Screate_simple(1, dims, nullptr);

    hid_t attr_id = H5Acreate(loc_id, name, type_id, space_id, H5P_DEFAULT, H5P_DEFAULT);
    if (attr_id < 0) {
        return false;
    }
    DECLARE_HDF5_RESOURCE_MANAGER(attr_id);
    auto status = H5Awrite(attr_id, type_id, value_ptr);
    return status >= 0;
}

struct SimpleDimension {
    static constexpr size_t max_ndim = 4;
    hsize_t                 dims[4];
    size_t                  ndim;
    hsize_t&                operator[](size_t i) { return dims[i]; }
    const hsize_t&          operator[](size_t i) const { return dims[i]; }
    void                    set_ndim(size_t ndim_) { ndim = ndim_; }

    SimpleDimension()
        : ndim(0) {}

    SimpleDimension(hsize_t s0)
        : ndim(1) {
        dims[0] = s0;
    }

    SimpleDimension(hsize_t s0, hsize_t s1)
        : ndim(2) {
        dims[0] = s0;
        dims[1] = s1;
    }

    SimpleDimension(hsize_t s0, hsize_t s1, hsize_t s2)
        : ndim(3) {
        dims[0] = s0;
        dims[1] = s1;
        dims[2] = s2;
    }

    SimpleDimension(hsize_t s0, hsize_t s1, hsize_t s2, hsize_t s3)
        : ndim(4) {
        dims[0] = s0;
        dims[1] = s1;
        dims[2] = s2;
        dims[3] = s3;
    }
};

inline bool is_dtype_resource_id(hid_t resource_id) {
    if (resource_id < 0) {
        return false;
    }
    SimpleHDF5ResourceKind dtype_resrouce_kind = get_resource_kind(resource_id);
    if (dtype_resrouce_kind != SimpleHDF5ResourceKind::structured_dtype &&
        dtype_resrouce_kind != SimpleHDF5ResourceKind::builtin_dtype) {
        return false;
    }
    return true;
}

inline bool is_abel_to_create_dataset(hid_t loc_id, const char* name) {
    if (loc_id < 0 || name == nullptr) {
        return false;
    }
    SimpleHDF5ResourceKind loc_kind = get_resource_kind(loc_id);
    if (loc_kind != SimpleHDF5ResourceKind::file && loc_kind != SimpleHDF5ResourceKind::group) {
        return false;
    }
    if (H5Lexists(loc_id, name, H5P_DEFAULT) > 0) {
        return false;
    }
    return true;
}
inline hid_t create_dataset_id(hid_t loc_id, const char* dataset_name, hid_t dtype_id,
                               const SimpleDimension& dataset_shape, hid_t link_plist_opt,
                               hid_t create_plist_opt, hid_t access_plist_opt) {
    if (!is_abel_to_create_dataset(loc_id, dataset_name)) {
        return INVALID_HDF5_RESOURCE_ID;
    }

    if (!is_dtype_resource_id(dtype_id)) {
        return INVALID_HDF5_RESOURCE_ID;
    }

    // check the shape
    for (size_t i = 0; i < dataset_shape.ndim; ++i) {
        if (dataset_shape[i] <= 0) {
            return INVALID_HDF5_RESOURCE_ID;
        }
    }

    hid_t space_id = H5Screate_simple(dataset_shape.ndim, dataset_shape.dims, nullptr);
    if (space_id < 0) {
        return INVALID_HDF5_RESOURCE_ID;
    }
    DECLARE_HDF5_RESOURCE_MANAGER(space_id);

    hid_t dataset_id = H5Dcreate(loc_id,
                                 dataset_name,
                                 dtype_id,
                                 space_id,
                                 link_plist_opt,
                                 create_plist_opt,
                                 access_plist_opt);
    return dataset_id;
}

template<class T>
hid_t create_dataset_id(hid_t loc_id, const char* dataset_name,
                        const SimpleDimension& dataset_shape, hid_t link_plist_opt,
                        hid_t create_plist_opt, hid_t access_plist_opt) {
    hid_t dtype_id = get_dtype_id<T>();
    CHECK_RESOURCE_ID_AND_RETURN(dtype_id, INVALID_HDF5_RESOURCE_ID);
    DECLARE_HDF5_RESOURCE_MANAGER(dtype_id);
    hid_t dataset_id = create_dataset_id(loc_id,
                                         dataset_name,
                                         dtype_id,
                                         dataset_shape,
                                         link_plist_opt,
                                         create_plist_opt,
                                         access_plist_opt);
    return dataset_id;
}

inline hid_t create_default_dataset_id(hid_t loc_id, const char* name, hid_t dtype_id,
                                       const SimpleDimension& data_shape) {
    return create_dataset_id(
        loc_id, name, dtype_id, data_shape, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
}

template<class T>
hid_t create_default_dataset_id(hid_t loc_id, const char* name, const SimpleDimension& data_shape) {
    return create_dataset_id<T>(loc_id, name, data_shape, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
}

inline hid_t create_zlib_compress_dataset_id(hid_t loc_id, const char* dataset_name, hid_t dtype_id,
                                             const SimpleDimension& data_shape,
                                             const SimpleDimension& data_chunk,
                                             int                    compress_level) {
    if (data_shape.ndim != data_chunk.ndim) {
        return INVALID_HDF5_RESOURCE_ID;
    }

    bool enable_chunk = true;
    for (size_t i = 0; i < data_shape.ndim; ++i) {
        if (data_shape[i] <= 0 || data_chunk[i] <= 0 || data_shape[i] < data_chunk[i]) {
            // LOG_WARN("the chunk dimension -> {} greater than data dimension -> {}",
            //          data_chunk[i],
            //          data_shape[i]);
            // return INVALID_HDF5_RESOURCE_ID;
            enable_chunk = false;
            break;
        }
    }
    hid_t dataset_id = INVALID_HDF5_RESOURCE_ID;
    if (enable_chunk) {
        auto avail = H5Zfilter_avail(H5Z_FILTER_DEFLATE);
        if (!avail) {
            return INVALID_HDF5_RESOURCE_ID;
        }

        uint32_t filter_info;
        if (H5Zget_filter_info(H5Z_FILTER_DEFLATE, &filter_info) < 0) {
            return INVALID_HDF5_RESOURCE_ID;
        }

        if (!(filter_info & H5Z_FILTER_CONFIG_DECODE_ENABLED) ||
            !(filter_info & H5Z_FILTER_CONFIG_ENCODE_ENABLED)) {
            return INVALID_HDF5_RESOURCE_ID;
        }
        hid_t create_plist_id = H5Pcreate(H5P_DATASET_CREATE);
        if (create_plist_id < 0) {
            return INVALID_HDF5_RESOURCE_ID;
        }

        DECLARE_HDF5_RESOURCE_MANAGER(create_plist_id);

        if (H5Pset_layout(create_plist_id, H5D_CHUNKED) < 0) {
            return INVALID_HDF5_RESOURCE_ID;
        }

        if (H5Pset_chunk(create_plist_id, data_chunk.ndim, data_chunk.dims) < 0) {
            return INVALID_HDF5_RESOURCE_ID;
        }
        if (H5Pset_deflate(create_plist_id, compress_level) < 0) {
            return INVALID_HDF5_RESOURCE_ID;
        }
        dataset_id = create_dataset_id(
            loc_id, dataset_name, dtype_id, data_shape, H5P_DEFAULT, create_plist_id, H5P_DEFAULT);
        // get the dtype size...
        size_t dtype_size = H5Tget_size(dtype_id);
        if (dtype_size == 0) {
            // unexpected!
            return INVALID_HDF5_RESOURCE_ID;
        }
        // fill unwritten data with zero
        std::vector<char> fill_values(dtype_size, 0);
        if (H5Pset_fill_value(create_plist_id, dtype_id, fill_values.data()) < 0) {
            // fail to set fill value!
            return INVALID_HDF5_RESOURCE_ID;
        }
    } else {
        dataset_id = create_dataset_id(
            loc_id, dataset_name, dtype_id, data_shape, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
    }

    return dataset_id;
}

template<class T>
hid_t create_zlib_compress_dataset_id(hid_t loc_id, const char* dataset_name,
                                      const SimpleDimension& data_shape,
                                      const SimpleDimension& data_chunk, int compress_level) {
    hid_t dtype_id = get_dtype_id<T>();
    CHECK_RESOURCE_ID_AND_RETURN(dtype_id, INVALID_HDF5_RESOURCE_ID);
    DECLARE_HDF5_RESOURCE_MANAGER(dtype_id);
    hid_t dataset_id = create_zlib_compress_dataset_id(
        loc_id, dataset_name, dtype_id, data_shape, data_chunk, compress_level);
    return dataset_id;
}

inline std::vector<std::string_view> split_path(std::string_view path, size_t& max_len) {
    std::vector<std::string_view> result;
    size_t                        n    = 0;
    size_t                        left = 0;
    for (size_t i = 0; i < path.size(); ++i) {
        if (path[i] == '/') {
            result.push_back(path.substr(left, i - left));
            n    = std::max(n, i - left);
            left = i + 1;
        }
    }
    result.push_back(path.substr(left, path.size() - left));
    n       = std::max(path.size() - left, n);
    max_len = n;
    return result;
}

inline bool write_dataset(hid_t dataset_id, const void* data_ptr, hid_t mem_dtype_id,
                          const SimpleDimension& data_shape, const SimpleDimension& data_offset,
                          hid_t space_id, hid_t chunk_space_id) {
    auto status = H5Sselect_hyperslab(
        space_id, H5S_SELECT_SET, data_offset.dims, nullptr, data_shape.dims, nullptr);
    if (status < 0) {
        return false;
    }
    status = H5Dwrite(dataset_id, mem_dtype_id, chunk_space_id, space_id, H5P_DEFAULT, data_ptr);
    if (status < 0) {
        return false;
    }
    return true;
}

inline bool write_dataset(hid_t dataset_id, const void* data_ptr, hid_t mem_dtype_id,
                          const SimpleDimension& data_shape, const SimpleDimension& data_offset,
                          hid_t space_id) {
    auto status = H5Sselect_hyperslab(
        space_id, H5S_SELECT_SET, data_offset.dims, nullptr, data_shape.dims, nullptr);
    if (status < 0) {
        return false;
    }

    hid_t chunk_space_id = H5Screate_simple(2, data_shape.dims, nullptr);
    if (chunk_space_id < 0) {
        return false;
    }
    DECLARE_HDF5_RESOURCE_MANAGER(chunk_space_id);
    status = H5Dwrite(dataset_id, mem_dtype_id, chunk_space_id, space_id, H5P_DEFAULT, data_ptr);
    if (status < 0) {
        return false;
    }
    return true;
}

template<class T>
bool write_dataset(hid_t dataset_id, const T* data_ptr, const SimpleDimension& data_shape,
                   const SimpleDimension& data_offset) {
    if (data_shape.ndim != data_offset.ndim) {
        return false;
    }
    if (dataset_id < 0) {
        return false;
    }
    hid_t dataspace_id = H5Dget_space(dataset_id);
    if (dataspace_id < 0) {
        return false;
    }
    DECLARE_HDF5_RESOURCE_MANAGER(dataspace_id);

    int ndim = H5Sget_simple_extent_ndims(dataspace_id);
    if (ndim != data_shape.ndim || ndim > data_shape.max_ndim) {
        return false;
    }
    hsize_t dataset_dims[data_shape.max_ndim];
    H5Sget_simple_extent_dims(dataspace_id, dataset_dims, nullptr);
    // whether overflow!
    for (size_t i = 0; i < ndim; ++i) {
        if (data_shape[i] + data_offset[i] > dataset_dims[i]) {
            return false;
        }
    }

    auto status = H5Sselect_hyperslab(
        dataspace_id, H5S_SELECT_SET, data_offset.dims, nullptr, data_shape.dims, nullptr);
    if (status < 0) {
        return false;
    }

    hid_t chunk_dataspace_id = H5Screate_simple(ndim, data_shape.dims, nullptr);
    CHECK_RESOURCE_ID_AND_RETURN(chunk_dataspace_id, false);
    DECLARE_HDF5_RESOURCE_MANAGER(chunk_dataspace_id);

    hid_t data_type_id = get_dtype_id<T>();
    CHECK_RESOURCE_ID_AND_RETURN(data_type_id, false);
    DECLARE_HDF5_RESOURCE_MANAGER(data_type_id);

    status =
        H5Dwrite(dataset_id, data_type_id, chunk_dataspace_id, dataspace_id, H5P_DEFAULT, data_ptr);
    if (status < 0) {
        return false;
    }
    return true;
}

inline hid_t create_group_id(hid_t loc_id, const char* name) {
    if (!is_abel_to_create_dataset(loc_id, name)) {
        return INVALID_HDF5_RESOURCE_ID;
    }
    hid_t group_id = H5Gcreate(loc_id, name, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
    return group_id;
}

template<class T> bool write_dataset(hid_t dataset_id, const T* data_ptr) {
    if (get_resource_kind(dataset_id) != SimpleHDF5ResourceKind::dataset) {
        return false;
    }
    hid_t dataspace_id = H5Dget_space(dataset_id);
    if (dataspace_id < 0) {
        return false;
    }
    DECLARE_HDF5_RESOURCE_MANAGER(dataspace_id);

    int ndim = H5Sget_simple_extent_ndims(dataspace_id);
    if (ndim > SimpleDimension::max_ndim) {
        return false;
    }

    // msvc not support the vla!
    hsize_t dims[SimpleDimension::max_ndim];
    H5Sget_simple_extent_dims(dataspace_id, dims, nullptr);

    SimpleDimension data_offset;
    data_offset.ndim = ndim;
    for (size_t i = 0; i < ndim; ++i) {
        data_offset.dims[i] = 0;
    }

    SimpleDimension data_shape;
    data_shape.ndim = ndim;
    for (size_t i = 0; i < ndim; ++i) {
        data_shape.dims[i] = dims[i];
    }
    return write_dataset(dataset_id, data_ptr, data_shape, data_offset);
}

inline std::vector<std::string> get_all_attr_names(hid_t loc_id) {
    std::vector<std::string> attr_names;
    if (loc_id < 0) {
        return attr_names;
    }
    H5O_info2_t obj_infos;
    H5Oget_info(loc_id, &obj_infos, H5O_INFO_NUM_ATTRS);
    int num_attrs = obj_infos.num_attrs;
    attr_names.reserve(num_attrs);

    for (int i = 0; i < num_attrs; ++i) {
        // cao
        auto attr_name_size =
            H5Aget_name_by_idx(loc_id, ".", H5_INDEX_NAME, H5_ITER_INC, i, nullptr, 0, H5P_DEFAULT);
        std::string attr_name(attr_name_size, 0);
        H5Aget_name_by_idx(loc_id,
                           ".",
                           H5_INDEX_NAME,
                           H5_ITER_INC,
                           i,
                           attr_name.data(),
                           attr_name.size() + 1,
                           H5P_DEFAULT);
        attr_names.push_back(std::move(attr_name));
    }
    return attr_names;
}

inline bool copy_attr(hid_t src_loc_id, hid_t dst_loc_id, const char* attr_name) {
    if (H5Aexists(src_loc_id, attr_name) <= 0) {
        return false;
    }

    if (H5Aexists(dst_loc_id, attr_name) > 0) {
        return false;
    }

    hid_t src_attr_id = H5Aopen(src_loc_id, attr_name, H5P_DEFAULT);
    CHECK_RESOURCE_ID_AND_RETURN(src_attr_id, false);
    DECLARE_HDF5_RESOURCE_MANAGER(src_attr_id);

    hid_t type_id = H5Aget_type(src_attr_id);
    CHECK_RESOURCE_ID_AND_RETURN(type_id, false);
    DECLARE_HDF5_RESOURCE_MANAGER(type_id);


    hid_t space_id = H5Aget_space(src_attr_id);
    CHECK_RESOURCE_ID_AND_RETURN(space_id, false);
    DECLARE_HDF5_RESOURCE_MANAGER(space_id);

    hid_t dst_attr_id =
        H5Acreate(dst_loc_id, attr_name, type_id, space_id, H5P_DEFAULT, H5P_DEFAULT);
    CHECK_RESOURCE_ID_AND_RETURN(dst_attr_id, false);
    DECLARE_HDF5_RESOURCE_MANAGER(dst_attr_id);

    // process the dynamic lenght string ...
    int element_size = H5Sget_simple_extent_npoints(space_id);
    if (H5Tget_class(type_id) == H5T_STRING && H5Tis_variable_str(type_id)) {
        // LOG_INFO("process dynamic length string attr {}", attr_name);
        std::vector<char*> ptr_buf(element_size);
        H5Aread(src_attr_id, type_id, ptr_buf.data());
        H5Awrite(dst_attr_id, type_id, ptr_buf.data());
        H5Dvlen_reclaim(type_id, space_id, H5P_DEFAULT, ptr_buf.data());
    } else {
        // process the simple type attr!
        int               type_size = H5Tget_size(type_id);
        std::vector<char> buf(element_size * type_size);
        H5Aread(src_attr_id, type_id, buf.data());
        H5Awrite(dst_attr_id, type_id, buf.data());
    }
    return true;
}


}   // namespace h5